<?php
require_once('FilterInput.class.php');
class Security {
	protected $type = 'string';
	protected $tagsMethod = 0;
	protected $attrMethod = 0;
	
	protected $xssAuto = 1;
	protected $tagsFilter = array ();
	protected $attrFilter = array ();
	
	protected $tagBlacklist  = array ('applet', 'body', 'bgsound', 'base', 'basefont', 'embed', 'frame', 'frameset', 'head', 'html', 'id', 'iframe', 'ilayer', 'layer', 'link', 'meta', 'name', 'object', 'script', 'style', 'title', 'xml');
	protected $attrBlacklist = array ('action', 'background', 'codebase', 'dynsrc', 'lowsrc');
	private static $_instance;
	private $inputFilter;
	private function __construct($type='string',$inputConfig = null) {

		if(isset($inputConfig)){
			$this->tagsMethod = $inputConfig ['tagsMethod'];
			$this->attrMethod = $inputConfig ['attrMethod'];
			$this->xssAuto = $inputConfig ['xssAuto'];
			$this->tagsFilter = $inputConfig ['tagsFilter'] ? $inputConfig ['tagsFilter'] : array ();
			$this->attrFilter = $inputConfig ['attrFilter'] ? $inputConfig ['attrFilter'] : array ();
			$this->tagBlacklist = $inputConfig ['tagBlacklist'];
			$this->attrBlacklist = $inputConfig ['attrBlacklist'];
		}
		$this->type = $type;
	}
	
	public static function getInstance($type = 'string',$config = null){
		return new self($type,$config);
	}
	
	public function setTagsMethod($switch){
		$this->tagsMethod = intval($switch)?1:0;
	}
	public function setAttrMethod ($switch){
		$this->attrMethod = intval($switch)?1:0;
	}
	public function setType($type){
		Assert::assertType('string',$type);
		$this->type = $type;
	}
	public function setXss($switch){
		$this->xssAuto = intval($switch)?1:0;
	}
	public function setTagsFilter($tags){
		$this->appendList('tagsFilter',$tags,true);
	}
	
	public function setTagBlacklist($tags){
		$this->appendList('tagBlacklist',$tags);
	}
	
	public function setAttrBlacklist($tags){
		$this->appendList('attrBlacklist',$tags);
	}
	
	public function setAttrFilter($tags){
		$this->appendList('attrFilter',$tags);
	}
	private function appendList($attrName,$tags,$replace = false){
		if(empty($tags) || is_numeric($tags)) {
			throw new InvalidArgumentException;
		}
		
		if(is_array($tags)){
			if($replace){
				$this->$attrName = $tags;
			}else{
				$this->$attrName = array_merge($this->$attrName,$tags);
			}
			return true;
		}
		
		if(strpos($tags,',') === FALSE){
			array_push($this->$attrName,$tags);
		}else{
			$newTags = explode(',',$tags);
			if($replace){
				$this->$attrName = $newTags;
			}else{
				$this->$attrName = array_merge($this->$attrName,$newTags);
			}
		}
	}
	public function inputFilter($input,$type = null) {
		if(isset($type)) {
			Assert::assertType($type,'string');
			$this->type = $type;
		}
		$output = $input;
		if(is_array($output)){
		     foreach ( $output as &$value ) {
                $value = $this->filterSource($value);
             }
		}
		if(is_string($output)){
			$output = $this->filterSource($output);
		}
		return $output;
	}
	
    /**
     * 过滤掉非字母
     *
     * @param string $value 要过滤的值
     *
     * @return string 过滤后的值
     */
    public static function filterAlpha($value){
		return self::pregReplaceString($value,"/[^a-zA-Z]/");
    }
    
  	public static function filterChinese($value){
		return self::pregReplaceString($value,"/[^\x80-\xff]/");
  	}
  	protected static function pregReplaceString($value,$pattern){
  		if (!self::_unicodeEnabled()){
            $pattern = $pattern.'u';
        }
        return preg_replace($pattern, '', (string)$value);
  	}  
	protected function filterSource($inputValue) {
		$this->setFilterInput();
		return $this->inputFilter->clean ( $inputValue, $this->type );
	}
	
	protected function setFilterInput(){
		$this->inputFilter = FilterInput::getInstance ( $this->tagsFilter, $this->attrFilter, $this->tagsMethod, $this->attrMethod, $this->xssAuto );
		if ($this->tagBlacklist) {
			$this->inputFilter->setTagBlacklist ( $this->tagBlacklist );
		}
		if ($this->attrBlacklist) {
			$this->inputFilter->setAttrBlacklist ( $this->attrBlacklist );
		}
	}
	
    /**
     * 确认 PCRE 是否支持 utf8 和 unicode
     *
     * @return boolean
     */
    static protected function _unicodeEnabled(){
        static $enabled = null;
        if (is_null($enabled)){
            $enabled = (@preg_match('/\pL/u', 'a')) ? true : false;
        }
        return $enabled;
    }
}